#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cassert>
#include <functional>
#include "Sock.hpp"
#include "Log.hpp"
#include "Epoller.hpp"

using namespace std;
const static int gport = 8080;
static const int gnum = 64;
using func_t = function<string(string)>;

class EpollServer{

public:
    EpollServer(func_t func, uint16_t port = gport): func_(func), port_(port){

    }

    void InitServer(){
        listenSock_.Socket();
        listenSock_.Bind(port_);
        listenSock_.Listen();
        epoller_.Create();

        logMessage(Debug, "init server success");
    }

    void Accepter(){
        string clientIp;
        uint16_t clientPort;
        int sock = listenSock_.Accept(&clientIp, &clientPort);
        if(sock < 0)
            return;

        logMessage(Debug, "[%s: %d], sock: %d", clientIp.c_str(), clientPort, sock);

        bool r = epoller_.AddEvent(sock, EPOLLIN);
        assert(r);
        (void)r;
    }

    void Recer(int index){
        int fd = revs_[index].data.fd;
        char req[1024];
        ssize_t s = recv(fd, req, sizeof(req)-1, 0);
        if(s > 0){
            req[s-1] = 0;
            req[s-2] = 0;

            cout << "client#" << fd << ": " << req << endl;

            string resp = func_(req);
            send(fd, resp.c_str(), resp.size(), 0);
        }
        else{
            if(s == 0)
                logMessage(Info, "client quit ...");
            else
                logMessage(Warning, "recv error, client quit ...");
            epoller_.DelEvent(fd);
            close(fd);
        }
    }

    void HandlerEvent(int num){
        for(int i = 0; i < num; i++){
            int fd = revs_[i].data.fd;
            uint32_t events = revs_[i].events;

            logMessage(Debug, "当前正在处理%d上的%s", fd, (events & EPOLLIN) ? "EPOLLIN" : "OTHER");

            if(events & EPOLLIN){
                if(fd == listenSock_.GetSock())
                    Accepter();
                else
                    Recer(i);
            }
        }
    }

    void Start(){
        bool r = epoller_.AddEvent(listenSock_.GetSock(), EPOLLIN);
        assert(r);
        (void)r;

        int timeout = -1;

        while(true){
            int timeout = -1;
            int n = epoller_.Wait(revs_, gnum, timeout);
            switch(n){
                case 0:
                    logMessage(Debug, "timeout");
                    break;
                case -1:
                    logMessage(Warning, "epoll_wait fail");
                    break;
                default:
                    logMessage(Debug, "happen: %d", n);
                    HandlerEvent(n);
                    break;
            }
            //sleep(1);
        }
    }

    ~EpollServer(){
        listenSock_.Close();
        epoller_.Close();
    }

private:
    uint16_t port_;
    Sock listenSock_;
    Epoller epoller_;
    struct epoll_event revs_[gnum];
    func_t func_;
};